package top.jnaw.jee.utils;

import com.alibaba.druid.filter.stat.StatFilter;
import com.alibaba.druid.wall.WallFilter;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.jfinal.kit.PropKit;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.ActiveRecordPlugin;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.DbKit;
import com.jfinal.plugin.activerecord.DbPro;
import com.jfinal.plugin.activerecord.Record;
import com.jfinal.plugin.druid.DruidPlugin;
import java.util.HashMap;
import java.util.List;
import top.jnaw.jee.platform.Consts.Result;

/**
 * Created by lc on 17-6-19.
 *
 * 数据库工具类
 */
public class DBs {

  private static HashMap<String, DBs> DBMaps = new HashMap<>();

  private ActiveRecordPlugin activeRecord;
  private DruidPlugin druid;
  private DbPro db;
  private String config;
  private String name;
  private JSONArray tables = new JSONArray();
  private JSONObject connectionInfo = new JSONObject();

  /**
   * 获取指定配置的数据库工具类
   *
   * @param config 配置名称
   * @return 工具类
   */
  public static DBs getByConfig(String config) {
    return DBMaps.get(config);
  }

  /**
   * 获取当前的数据库基础信息，含表名、字段名、类型、是否为主键、注释
   */
  public JSONArray getTables() {
    if (tables.size() > 0) {
      return tables;
    }

    if (StrKit.isBlank(name) || null == db || null == druid
        || null == activeRecord) {
      return tables;
    }

    List<Record> list = db.find("SELECT"
        + "   TABLE_NAME AS `table`,"
        + "   COLUMN_NAME AS `columns.name`,"
        + "   COLUMN_TYPE AS `columns.type`,"
        + "   COLUMN_KEY AS `columns.key`,"
        + "   COLUMN_COMMENT AS `columns.comment`"
        + " FROM `information_schema`.`COLUMNS`"
        + " WHERE"
        + "   TABLE_SCHEMA = ?", this.name);

    // [Neo] .TODO
//    tables = Models.compressList(list);
    return tables;
  }

  /**
   * 获取指定数据表的前五行
   *
   * @param table 表名
   */
  public JSONObject getRows(String table) {
    return getRows(table, 5);
  }

  public boolean isClosed() {
    return true;
  }

  /**
   * 获取数据表数据
   *
   * @param table 表明
   * @param limit 限制行数，-1 表示不限制
   */
  public JSONObject getRows(String table, int limit) {
    if (StrKit.isBlank(table) || StrKit.isBlank(config) || null == druid
        || null == activeRecord) {
      return null;
    }

    List<Record> list;
    if (limit < 0) {
      list = db.find("SELECT * FROM ?", "`" + this.name + "`.`" + table + "`");
    } else {
      list = db.find("SELECT * FROM ? LIMIT ?",
          "`" + this.name + "`.`" + table + "`", limit);
    }

    return Models.toJson(list, false, Result.kSuccess);
  }

  /**
   * 获取当前的配置名称
   */
  public String getConfig() {
    return config;
  }

  /**
   * 获取当前的数据库操作类
   */
  public DbPro getDb() {
    return db;
  }

  /**
   * 创建数据库连接，最大只有 2 个连接数
   *
   * @param config 配置名称
   * @param host 数据库主机
   * @param port 数据库端口
   * @param db 数据库名称
   * @param user 数据库用户名
   * @param password 数据库密码
   * @param server_time 服务器时区是否正确
   * @return 是否成功连接
   */
  public boolean start(String config, String host,
      int port, String db, String user, String password, boolean server_time) {
    return start(config, host, port, db, PropKit.get("db_encode"), user,
        password, 3, 1, server_time);
  }

  /**
   * 创建数据库连接
   *
   * @param config 配置名称
   * @param host 数据库主机
   * @param port 数据库端口
   * @param db 数据库名称
   * @param encode 数据库编码
   * @param user 数据库用户名
   * @param password 数据库密码
   * @param max 最大连接数
   * @param min 最小连接数
   * @param server_time 服务器时区是否正确
   * @return 是否连接成功
   */
  public boolean start(String config, String host, int port, String db,
      String encode, String user, String password, int max, int min,
      boolean server_time) {
    boolean result = false;

    synchronized (DBs.class) {
      DBs old = DBMaps.get(config);

      if (null != old) {
        // [Neo] TODO
        Log.w("old config is not null");

        return true;
      }

      this.name = db;
      this.config = config;
      String jdbcUrl;
      if (server_time) {
        jdbcUrl = String
            .format(Generator.DB_FORMATTERS[Generator.DBType.MYSQL.ordinal()],
                host, port, db, encode);
      } else {
        jdbcUrl = String
            .format(Generator.DB_FORMATTERS[Generator.DBType.MYSQL.ordinal()],
                host, port, db, encode) + "&serverTimezone=GMT";
      }

      druid = new DruidPlugin(jdbcUrl, user, password);
      druid.setMaxActive(max);
      druid.setMinIdle(min);
      druid.setInitialSize(min);
      druid.setConnectionInitSql(Db.getSql("support-full-group"));

      WallFilter wall = new WallFilter();
      wall.setDbType(Generator.DB_TYPE_NAMES[Generator.DBType.MYSQL.ordinal()]);
      druid.addFilter(wall);
      druid.addFilter(new StatFilter());

      result = druid.start();

      if (result) {
        activeRecord = new ActiveRecordPlugin(config, druid);
        activeRecord.setShowSql(PropKit.getBoolean("show_sql"));
        result = activeRecord.start();

        connectionInfo.put("host", host);
        connectionInfo.put("port", port);
        connectionInfo.put("password", password);
        connectionInfo.put("db", db);
        connectionInfo.put("user", user);

        // TODO add timer for auto-close
        DBMaps.put(config, this);
        this.db = Db.use(config);
      }

    }

    return result;
  }

  /**
   * 终止数据库连接
   *
   * @return 是否成功
   */
  public boolean stop() {
    boolean result = false;

    if (null != druid) {
      druid.stop();
      druid = null;
    }

    if (null != activeRecord) {
      result = activeRecord.stop();
      activeRecord = null;

      DBMaps.remove(config);
      DbKit.removeConfig(config);

      config = null;

      name = null;
      tables = null;
    }

    return result;
  }

  /**
   * 获取连接信息
   */
  public JSONObject getConnectionInfo() {
    return connectionInfo;
  }

}
